﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Web;

namespace com.eforceglobal.crux.web.wrokflows
{
    public static class ConfigParser
    {
        private static XDocument LoadConfigurationDocument()
        {
            XDocument xDocument = (XDocument)HttpRuntime.Cache.Get("WorkflowConfigurationFile");
            if (xDocument == null)
            {
                string fileName = HttpContext.Current.Server.MapPath("~/SiteConfig/workflows.xml");
                xDocument = XDocument.Load(fileName);
                HttpRuntime.Cache.Add("WorkflowConfigurationFile", xDocument, new System.Web.Caching.CacheDependency(fileName), DateTime.Now.AddDays(7),
                TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null);
            }
            return xDocument;
        }
        public static Workflow GetWorkflowConfiguration(string WorkflowName)
        {
            Workflow workflow = new Workflow();
            XElement workflowElement = GetWorkflowElement(WorkflowName);
            workflow.WorkflowName = workflowElement.Attribute("Name").Value;
            workflow.Activites = GetActivitiesForWorflow(WorkflowName);
            string StartAcitivityName = workflowElement.Attribute("StartActivity").Value;
            string EndAcitivityName = workflowElement.Attribute("EndActivity").Value;
            workflow.StartActivity = GetActivity(WorkflowName, StartAcitivityName);
            workflow.EndActivity = GetActivity(WorkflowName, EndAcitivityName);
            return workflow;
        }

        public static Action GetAction(string WorkflowName, string ActivityName, string ActionName)
        {
            XElement activityConfiguration = GetActivityElement(WorkflowName, ActivityName);
            XElement actionElement = activityConfiguration.Element("Actions")
                                                            .Elements("Action")
                                                            .Single(p => p.Attribute("Name").Value == ActionName);
            Action action = new Action();
            action.ActionName = actionElement.Attribute("Name").Value;

            if (actionElement.Attribute("ResultantActivity") != null)
                action.ResultantAcitivity = actionElement.Attribute("ResultantActivity").Value;

            if (actionElement.Attribute("ActionClass") != null)
            {
                string[] DllClassName = actionElement.Attribute("ActionClass").Value.Split(',');
                string ClassName = DllClassName[0].Trim();
                string DllName =  DllClassName[1].Trim();
                action.ActionDll = DllName;
                action.ActionClass = ClassName;
            }
            return action;
        }

        public static Activity GetActivity(string WorkFlowName, string ActivityName)
        {
            XElement activityConfiguration = GetActivityElement(WorkFlowName, ActivityName);
            Activity activity = GetAcitvityFromConfiguration(activityConfiguration);
            activity.Actions = GetActionsForActivity(WorkFlowName, ActivityName);
            return activity;
        }

        private static List<Activity> GetActivitiesForWorflow(string WorkFlowName)
        {
            XElement workflowElement = GetWorkflowElement(WorkFlowName);
            IEnumerable<XElement> activityDetails = workflowElement.Element("Activities").Elements("Activity");
            List<Activity> activities = new List<Activity>();
            foreach (XElement activityConfiguration in activityDetails)
            {
                Activity activity = GetActivity(WorkFlowName, activityConfiguration.Attribute("Name").Value);
                activities.Add(activity);
            }
            return activities;
        }

        private static List<Action> GetActionsForActivity(string WorkFlowName, string ActivityName)
        {
            XElement activityConfiguration = GetActivityElement(WorkFlowName, ActivityName);
            XElement actionsElements = activityConfiguration.Element("Actions");
            IEnumerable<XElement> activityActionsConfiguration = new List<XElement>();
            if(actionsElements!=null)
                activityActionsConfiguration = actionsElements.Elements("Action");
            
            List<Action> actions = new List<Action>();

            foreach (XElement actionConfiguration in activityActionsConfiguration)
            {
                Action action = GetAction(WorkFlowName, ActivityName, actionConfiguration.Attribute("Name").Value);
                actions.Add(action);
            }
            return actions;
        }

        
        private static XElement GetActivityElement(string WorkflowName, string ActivityName)
        {
            XElement workflow = GetWorkflowElement(WorkflowName);
            XElement activityConfiguration = workflow.Element("Activities")
                                                     .Elements("Activity")
                                                     .SingleOrDefault(p => p.Attribute("Name").Value == ActivityName);
            if (activityConfiguration == null) throw CruxWorkflowExceptions.AcitivityNotFoundInWorkflowException;
            return activityConfiguration;
            
        }

        private static Activity GetAcitvityFromConfiguration(XElement AcivitiyConfigurationElement)
        {
            string ActivityName = AcivitiyConfigurationElement.Attribute("Name").Value;
            string WorkflowName = AcivitiyConfigurationElement.Parent.Parent.Attribute("Name").Value;
            string DefaultInstanceName = "";
            Activity activity = new Activity();
            if (AcivitiyConfigurationElement.Attribute("DefaultAction") != null)
            {
                DefaultInstanceName = AcivitiyConfigurationElement.Attribute("DefaultAction").Value;
                activity.DefaultAction = GetAction(WorkflowName, ActivityName, DefaultInstanceName);
            }
            activity.ActivityName = ActivityName;
            if(AcivitiyConfigurationElement.Attribute("NextActivity") != null)
                activity.NextActivity = AcivitiyConfigurationElement.Attribute("NextActivity").Value;
            if (AcivitiyConfigurationElement.Attribute("PreviousActivity") != null)
                activity.PreviousActivity = AcivitiyConfigurationElement.Attribute("PreviousActivity").Value;
            activity.State = AcivitiyConfigurationElement.Attribute("State").Value;
            
            return activity;
        }

       

        private static XElement GetWorkflowElement(string WorkFlowName)
        {
            XDocument configurationDocument = LoadConfigurationDocument();
            XElement workflowElement = configurationDocument.Elements("Workflows")
                                            .Elements("Workflow")
                                            .SingleOrDefault(p => p.Attribute("Name").Value == WorkFlowName);
            if (workflowElement == null) throw CruxWorkflowExceptions.WorkflowConfigurationNotFoundException;
            return workflowElement;
        }

    }
}
